package com.liuyjy.mybatisplus.util;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.FileType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;

/**
 * @Author liuyjy
 * @Date 2022/1/18 13:07
 * @Description: 生成配置
 **/
public class GenerateUtil {
    private Logger logger = LoggerFactory.getLogger(GenerateUtil.class);


    private static final String DRIVER="com.mysql.jdbc.Driver";
    /**
     * 数据库链接
     */
    private String url;
    /**
     * 用户名
     */
    private String username;
    /**
     * 密码
     */
    private String password;
    /**
     * 项目路径
     */
    private String packages;
    /**
     * 作者
     */
    private String author;

    /**
     * 表名
     */
    private String table;

    /**
     * 生成目录
     */
    private String outputDir;

    /**
     * 模块名
     */
    private String module;

    private String applicationName;

    /**
     * 是否生成swagger2
     */
    private boolean swagger2;

    /**
     * xml文件生成目录
     */
    private String outputXmlUrl;
    /**
     * api文件生成目录
     */
    private String outputApiUrl;
    /**
     * sever文件生成目录
     */
    private String outputServerUrl;


    /**
     * 读取配置文件
     * @param jdbcStream 文件
     */
    private void init(InputStream jdbcStream) {
        try {
            Properties jdbcProperties = new Properties();
            if (jdbcStream == null) {
                logger.error(".properties 文件不存在！");
                //System.out.println("resources/generate-jdbc.properties 文件不存在");
                return;
            }
            jdbcProperties.load(jdbcStream);
            username = jdbcProperties.getProperty("username");
            if (StringUtils.isBlank(username)) {
                logger.error("数据库用户名没填！");
                return;
            }
            password = jdbcProperties.getProperty("password");
            if (StringUtils.isBlank(password)) {
                logger.error("数据库密码没填！");
                return;
            }
            url = jdbcProperties.getProperty("url");
            if (StringUtils.isBlank(url)) {
                logger.error("数据库链接没填！");
                return;
            }

            table = jdbcProperties.getProperty("table");
//            if(StringUtils.isEmpty(table)){
//                logger.error("表名没填！");
//                return;
//            }
            applicationName=jdbcProperties.getProperty("applicationName");
            if(StringUtils.isBlank(applicationName)){
                logger.error("服务名没填！");
                return;
            }

            outputDir = jdbcProperties.getProperty("outputDir");
            if (StringUtils.isBlank(outputDir)) {
                outputDir = System.getProperty("user.dir");
            }
            outputXmlUrl = jdbcProperties.getProperty("outputDirXml");

            outputServerUrl = jdbcProperties.getProperty("outputDirSever");

            outputApiUrl = jdbcProperties.getProperty("outputDirApi");

            module = jdbcProperties.getProperty("module");
            if (StringUtils.isBlank(module)) {
                logger.error("模块名没填！");
                return;
            }

            packages = jdbcProperties.getProperty("packages");
            if (StringUtils.isBlank(packages)) {
                logger.error("包名没填！");
                return;
            }
            author=jdbcProperties.getProperty("author");
            String swagger21 = jdbcProperties.getProperty("swagger2");
            if (StringUtils.isNotBlank(swagger21)) {
                swagger2 = Boolean.parseBoolean(swagger21);
            }


            if (StringUtils.isBlank(outputXmlUrl)) {
                outputXmlUrl = outputDir + "/xml/" + module;
            } else {
                outputXmlUrl = outputDir + outputXmlUrl + "/" + module;
            }

            String moduleUrl = "/" + packages.replace(".", "/") + "/" + module;

            if (StringUtils.isBlank(outputApiUrl)) {
                outputApiUrl = outputDir + moduleUrl;
            } else {
                outputApiUrl = outputDir + outputApiUrl + moduleUrl;
            }

            if (StringUtils.isBlank(outputServerUrl)) {
                outputServerUrl = outputDir + moduleUrl;
            } else {
                outputServerUrl = outputDir + outputServerUrl + moduleUrl;
            }

            if (url.length() > password.length()) {
                logger.info("数据读取成功！");
                //System.out.println("数据读取成功");
            }
        } catch (IOException e) {
            logger.error("读取文件失败");
            e.printStackTrace();
        } catch (NullPointerException e) {
            logger.error("读取数据失败,查看配置文件的key是否匹配");
            e.printStackTrace();
        }
    }

    /**
     * 生成文件
     *
     * @param jdbcStream 文件
     */
    public void create(InputStream jdbcStream) {
        //初始化数据
        init(jdbcStream);

        AutoGenerator mpg = new AutoGenerator();

        mpg.setTemplateEngine(new FreemarkerTemplateEngine());
        // 全局配置
        globalConfig(mpg);
        // 数据源配置
        sourceConfig(mpg);
        //包配置
        packageConfig(mpg);
        // 策略配置
        strategyConfig(mpg);
        //配置模板
        templateConfig(mpg);

        //自定义配置
        injectionConfig(mpg);
        // 执行生成
        mpg.execute();
    }

    /**
     * 策略配置
     * @param mpg 配置文件
     */
    private void strategyConfig (AutoGenerator mpg) {
        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        //数据库表映射到实体的命名策略
        strategy.setNaming(NamingStrategy.underline_to_camel);
        //数据库表字段映射到实体的命名策略
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        //lombok模型
        strategy.setEntityLombokModel(true);
        //生成 @RestController 控制器
        strategy.setRestControllerStyle(true);
        strategy.setEntityTableFieldAnnotationEnable(true);
        strategy.setControllerMappingHyphenStyle(true);
        //表前缀
        //strategy.setTablePrefix("t_");
        // strategy.setCapitalMode(true);// 全局大写命名 ORACLE 注意
        // 此处可以修改为您的表前缀
         strategy.setTablePrefix(new String[] { "t_", "tb_" });
        //strategy.setInclude(scanner("表名，多个英文逗号分割").split(","));
        // strategy.setInclude(new String[] { "user" }); // 需要生成的表
        // strategy.setExclude(new String[]{"test"}); // 排除生成的表
        if(StringUtils.isNotBlank(table)){
            strategy.setInclude(table.split(","));
        }
        mpg.setStrategy(strategy);
    }
    /**
     * 全局配置
     * @param mpg 配置文件
     */
    private void globalConfig (AutoGenerator mpg) {
        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        if(StringUtils.isBlank(outputDir)){
            String projectPath = System.getProperty("user.dir");
            gc.setOutputDir(projectPath + "/src/main/java");
        }else {
            gc.setOutputDir(outputDir);
        }
        gc.setFileOverride(true);

        gc.setActiveRecord(true);
        // XML 二级缓存
        gc.setEnableCache(false);
        // XML ResultMap
        gc.setBaseResultMap(true);
        // XML columList
        gc.setBaseColumnList(true);

        //作者
        gc.setAuthor(author);
        //打开输出目录
        gc.setOpen(true);
        // 实体属性 Swagger2 注解
        gc.setSwagger2(swagger2);

        // 自定义文件命名，注意 %s 会自动填充表实体属性！
        gc.setMapperName("%sMapper");
        //gc.setXmlName("%sMapper");
        gc.setServiceName("%sService");
        gc.setServiceImplName("%sServiceImpl");
        gc.setControllerName("%sRemoteImpl");
        mpg.setGlobalConfig(gc);
    }

    /**
     * 包配置
     * @param mpg 配置文件
     */
    private void packageConfig (AutoGenerator mpg) {
        // 包配置
        PackageConfig pc = new PackageConfig();
        Map<String, String> pathInfo = new HashMap<>();

        pathInfo.put(ConstVal.ENTITY_PATH, outputServerUrl + "/entity");
        pathInfo.put(ConstVal.MAPPER_PATH, outputServerUrl + "/mapper");
        pathInfo.put(ConstVal.CONTROLLER_PATH, outputServerUrl + "/remote");
        pathInfo.put(ConstVal.SERVICE_PATH, outputServerUrl + "/service");
        pathInfo.put(ConstVal.SERVICE_IMPL_PATH, outputServerUrl + "/service/impl");

        pathInfo.put("remote", outputApiUrl + "/remote");

        pathInfo.put(ConstVal.XML_PATH, outputXmlUrl);

        pc.setPathInfo(pathInfo);
        pc.setModuleName(module);
        pc.setParent(packages);
//                .setEntity("entity")
//                .setMapper("mapper")
//                .setService("service")
//                .setServiceImpl("service.impl")
//                .setController("remote");
        mpg.setPackageInfo(pc);
    }

    /**
     * 自定义配置
     * @param mpg
     */
    private void injectionConfig(AutoGenerator mpg) {

        // 自定义配置
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                // to do nothing
                Map<String, Object> map = Maps.newHashMap();
                map.put("remotePackage",packages+"."+module+".remote");
                map.put("remoteApiPackage",packages+"."+module+".remote");
                map.put("modelPackage",packages+"."+module+".dao");
                map.put("applicationName",applicationName);
                map.put("moduleName",module);
                String scApiServiceId = "${feign.client." + applicationName + ":}";
                map.put("scApiServiceId", scApiServiceId);
                map.put("moduleName",module);
                this.setMap(map);
            }
        };

        // 如果模板引擎是 freemarkercontroller3.java.ftl
        //String templatePath = "/templates/mapper.xml.ftl";
        // 如果模板引擎是 velocity
        // String templatePath = "/templates/mapper.xml.vm";


        // 自定义输出配置
        List<FileOutConfig> focList = new ArrayList<>();
//        // 自定义配置会被优先输出
//        focList.add(new FileOutConfig("/templates/mapper/mapper.xml.ftl") {
//            @Override
//            public String outputFile(TableInfo tableInfo) {
//                // 自定义输出文件名 ， 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化！！
//                return outputXmlUrl+ "/" + tableInfo.getEntityName() + "Mapper.xml";
//            }
//        });
        focList.add(new FileOutConfig("/templates/remote/remote.java.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return outputApiUrl + "/remote/" + tableInfo.getEntityName() + "Remote.java";
            }
        });

        focList.add(new FileOutConfig("/templates/entity/entityDao.java.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return outputApiUrl + "/dao/" + tableInfo.getEntityName() + "DTO.java";
            }
        });

        cfg.setFileCreate(new IFileCreate() {
            @Override
            public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) {
                // 判断自定义文件夹是否需要创建
                //checkDir("调用默认方法创建的目录，自定义目录用");
                checkDir(filePath);

                if (FileType.ENTITY == fileType) {
                    return true;
                }
                return !new File(filePath).exists();

            }
        });
        cfg.setFileOutConfigList(focList);
        mpg.setCfg(cfg);
    }


    /**
     * 配置模板
     * @param mpg 配置文件
     */
    private void templateConfig (AutoGenerator mpg) {
        // 配置模板
        TemplateConfig templateConfig = new TemplateConfig();

        // 配置自定义输出模板
        //指定自定义模板路径，注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
         templateConfig.setEntity("/templates/entity/entity.java");
        // templateConfig.setService();
        templateConfig.setController("templates/remote/remoteImpl.java");
        templateConfig.setMapper("templates/mapper/mapper.java");
        //templateConfig.setXml("");
        mpg.setTemplate(templateConfig);
    }

    /**
     * 配置数据源
     * @param mpg 配置文件
     */
    private void sourceConfig (AutoGenerator mpg) {
        // 数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setDbType(DbType.MYSQL);
        dsc.setDriverName(DRIVER);
        dsc.setUrl(url);
        dsc.setUsername(username);
        dsc.setPassword(password);
        mpg.setDataSource(dsc);
    }

    /**
     * 读取控制台内容
     */
    public String scanner(String tip) {
        Scanner scanner = new Scanner(System.in);
        StringBuilder help = new StringBuilder();
        help.append("请输入" + tip + "：");
        System.out.println(help.toString());
        if (scanner.hasNext()) {
            String ipt = scanner.next();
            if (StringUtils.isNotBlank(ipt)) {
                return ipt;
            }
        }
        throw new MybatisPlusException("请输入正确的" + tip + "！");
    }


}
